package com.dwy2002.user.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dwy2002.common.Result;
import com.dwy2002.common.exception.EmptyIdException;
import com.dwy2002.common.utils.Validator;
import com.dwy2002.enums.Status;
import com.dwy2002.pojo.dto.users.RoleDTO;
import com.dwy2002.pojo.po.users.Role;
import com.dwy2002.pojo.vo.users.RoleDetailVO;
import com.dwy2002.pojo.vo.users.RoleVO;
import com.dwy2002.user.mapper.RoleMapper;
import com.dwy2002.user.service.IPermissionService;
import com.dwy2002.user.service.IRolePermissionService;
import com.dwy2002.user.service.IRoleService;
import com.dwy2002.user.service.IRoleUserService;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import java.util.Collections;
import java.util.List;
import java.util.Optional;

import static com.dwy2002.common.Result.*;
import static com.dwy2002.common.utils.Utils.isEmptyOrNull;

/**
 * @author 杜伟毅
 * @version 1.0
 * @since 2025/03/16
 */
@Service
@RequiredArgsConstructor
public class RoleServiceImpl extends ServiceImpl<RoleMapper, Role> implements IRoleService {
    private final IRoleUserService roleUserService;
    private final IRolePermissionService rolePermissionService;
    private final IPermissionService permissionService;

    /**
     * 添加角色
     *
     * @param dto 角色DTO
     * @author 杜伟毅
     * @since 2025/3/16 0016 20:23
     */
    @Override
    public Result<Void> appendRole(RoleDTO dto) {
        Validator.of(dto)
                .notEmpty(RoleDTO::getRoleName, "角色名字不能为空")
                .validate();

        boolean save = save(BeanUtil.copyProperties(dto, Role.class));
        return saveResult(save, "添加成功", "添加失败");
    }

    /**
     * 修改角色
     *
     * @param dto 角色DTO
     * @author 杜伟毅
     * @since 2025/3/16 0016 22:47
     */
    @Override
    public Result<Void> updateRole(RoleDTO dto) {
        Validator.of(dto)
                .notEmpty(RoleDTO::getId, "id不能为空")
                .notEmpty(RoleDTO::getRoleName, "角色名字不能为空")
                .validate();

        Role role = getById(dto.getId());
        if (ObjectUtils.isEmpty(role)) fail(Status.BAD_REQUEST, "没有这个角色");

        LambdaUpdateWrapper<Role> luw = new LambdaUpdateWrapper<>();
        luw.eq(Role::getId, dto.getId())
                .set(!StringUtils.equals(role.getRoleName(), dto.getRoleName()), Role::getRoleName, dto.getRoleName());
        boolean update = update(luw);
        return handleResult(update, "修改成功", "修改失败");
    }

    /**
     * 返回所有角色
     *
     * @author 杜伟毅
     * @since 2025/3/16 0016 23:26
     */
    @Override
    public Result<List<Role>> getRole() {
        LambdaQueryWrapper<Role> lqw = new LambdaQueryWrapper<>();
        return success(list(lqw));
    }

    /**
     * 删除角色
     *
     * @param id 角色id
     * @author 杜伟毅
     * @since 2025/3/16 0016 23:38
     */
    @Override
    public Result<Void> removeRole(String id) {
        if (isEmptyOrNull(id)) return fail(Status.BAD_REQUEST, "id不能为空");
        Role role = getById(id);
        if (ObjectUtils.isEmpty(role)) return fail(Status.BAD_REQUEST, "删除失败，没有这个角色");
        if (id.equals("f546dbec33c2514a943db04953669f6d") || id.equals("d39bfb53b5e9352714b3f4288ab4ae5f"))
            return fail(Status.BAD_REQUEST, "受保护角色不可删除");
        //删除这个角色所拥有的权限关系
        rolePermissionService.deleteRolePermissionByRoleId(id);
        //将要删除的角色转移到临时角色
        roleUserService.updateRoleUsers(id);
        boolean remove = removeById(id);
        return handleResult(remove, "删除成功", "删除失败");
    }

    /**
     * 获取用户的角色
     *
     * @param id 用户id
     * @return 用户的角色
     * @author 杜伟毅
     * @since 2025/5/12 0012 21:13
     */
    @Override
    public RoleVO getUserRole(String id) {
        // 方法入口参数校验：确保输入的用户ID不为空或无效格式
        // 使用统一校验方法替代分散的判空逻辑，提高代码可维护性
        if (isEmptyOrNull(id)) {
            // 抛出业务异常时携带明确的错误信息，便于问题定位
            throw new EmptyIdException("getUserRole: 用户ID不能为空");
        }

        // 使用Optional包装输入参数，构建声明式处理管道
        return Optional.of(id) // 注意：此处使用of()而非ofNullable()，因为已通过前置校验确保id非空
                .map(userId -> {
                    /* 阶段一：获取角色标识
                     * ------------------------------------------------------------
                     * 调用角色用户服务获取与用户关联的角色ID
                     * 注意角色ID可能的返回值：
                     * 1. 有效角色ID（如"ROLE_ADMIN"）
                     * 2. 特定无角色标识（"无角色"）
                     * 3. null（理论上不会出现，因服务层应保证返回值确定性）
                     */
                    String roleId = roleUserService.getRoleIdByUserId(userId);

                    // 构建嵌套Optional处理管道，处理角色ID的多种情况
                    return Optional.ofNullable(roleId)
                            /* 阶段二：过滤无效角色标识
                             * --------------------------------------------------------
                             * 过滤条件说明：
                             * 1. 排除null值：当角色服务返回null时的处理
                             * 2. 排除"无角色"字符串：明确的无角色标识
                             * 这里使用!equals而非!=进行字符串比较，避免潜在的空指针异常
                             */
                            .filter(rid -> !"无角色".equals(rid))

                            /* 阶段三：角色信息与权限数据加载
                             * --------------------------------------------------------
                             * 使用flatMap实现多级Optional的扁平化处理：
                             * 1. 当存在有效角色ID时，尝试加载角色详细信息
                             * 2. 合并处理角色查询和权限加载操作，保持事务一致性
                             */
                            .flatMap(rid -> {
                                // 尝试从角色存储库获取角色实体
                                Role role = getById(rid);

                                // 处理角色不存在的情况（例如数据不一致或缓存过期）
                                if (role == null) {
                                    // 记录日志或触发告警的潜在位置（根据业务需求扩展）
                                    return Optional.empty();
                                }

                                /* 对象转换与权限加载
                                 * ----------------------------------------------------
                                 * 使用新建VO对象避免实体对象直接暴露给上层
                                 */
                                RoleVO vo = new RoleVO();
                                BeanUtils.copyProperties(role, vo);
                                vo.setPermCodes(permissionService.getPermCode(rid));

                                return Optional.of(vo);
                            })

                            /* 阶段四：处理无角色/角色无效的情况
                             * --------------------------------------------------------
                             * 当出现以下情况时进入此分支：
                             * 1. 角色ID为null（角色服务返回空）
                             * 2. 角色ID是"无角色"标识
                             * 3. 角色ID有效但数据库查询失败
                             */
                            .orElseGet(() -> {
                                // 构建默认无角色响应对象
                                RoleVO emptyVO = new RoleVO();
                                emptyVO.setRoleName("无角色");  // 明确标识无角色状态
                                emptyVO.setPermCodes(Collections.emptyList());  // 返回空集合而非null
                                return emptyVO;
                            });
                })
                /* 最终异常处理保障（理论上不会触发）
                 * ----------------------------------------------------------------
                 * 防御性编程设计：
                 * 1. 因入口已校验id非空，此处异常应仅在极端情况下出现
                 * 2. 保留此处理逻辑作为安全网（Safety Net）机制
                 */
                .orElseThrow(() -> new EmptyIdException("用户角色查询发生意外异常"));
    }

    /**
     * 获取角色详情
     *
     * @param id 角色id
     * @author 杜伟毅
     * @since 2025/5/14 0014 23:39
     */
    @Override
    public Result<RoleDetailVO> getRoleDetail(String id) {
        if (isEmptyOrNull(id)) throw new EmptyIdException("getRoleDetail: ID不能为空");
        RoleDetailVO roleDetail = BeanUtil.copyProperties(getById(id), RoleDetailVO.class);
        roleDetail.setPermissions(permissionService.getPermission(id));
        return success(roleDetail);
    }

    //----辅助方法-------------------------------------------------------------------
}
